/*
Copyright (C) 2004 Jacquelin POTIER <jacquelin.potier@free.fr>
Dynamic aspect ratio code Copyright (C) 2004 Jacquelin POTIER <jacquelin.potier@free.fr>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

//-----------------------------------------------------------------------------
// Object: manage Software Update
//-----------------------------------------------------------------------------
#include "softwareupdate.h"

//-----------------------------------------------------------------------------
// Name: CheckForUpdate
// Object: 
//          1) get last software release info from an xml file like
//          <PROGRAM_VERSION>3.1.3.0</PROGRAM_VERSION><PROGRAM_CHANGE_INFO>Software description</PROGRAM_CHANGE_INFO> (not case sensitive for markup)
//          this information is present in PAD files like those generated by PADGen
//          2) if a new version exist, allow user to download new version
// Parameters :
//     in  : TCHAR* UrlOfLastVersionInfoFile : url of xml file
//           DWORD VersionNbDigits : number of digits to check
//           TCHAR* DownloadLink : download link of last version
//     out :
//     return : TRUE on success
//-----------------------------------------------------------------------------
BOOL CSoftwareUpdate::CheckForUpdate(TCHAR* UrlOfLastVersionInfoFile,DWORD VersionNbDigits,TCHAR* DownloadLink)
{
    BOOL bNewVersionIsAvailable;
    return CSoftwareUpdate::CheckForUpdate(UrlOfLastVersionInfoFile,VersionNbDigits,DownloadLink,TRUE,&bNewVersionIsAvailable);
}
BOOL CSoftwareUpdate::CheckForUpdate(TCHAR* UrlOfLastVersionInfoFile,DWORD VersionNbDigits,TCHAR* DownloadLink,BOOL bDisplayDialog,BOOL* pbNewVersionIsAvailable)
{
    BOOL bSuccess=FALSE;
    char* pszContentUpper=NULL;
    PBYTE VersionInfoFileContent=NULL;
    ULONG VersionInfoFileContentSize=0;
    char* pszReport=NULL;
    TCHAR AppPath[MAX_PATH];

    // default return value
    *pbNewVersionIsAvailable = FALSE;

#if (defined(UNICODE)||defined(_UNICODE))
    char* pszAnsi;
#endif

    // get app path
    if(!CStdFileOperations::GetAppName(AppPath,MAX_PATH))
        return FALSE;

    // get app version
    CVersion Version;
    if(!Version.Read(AppPath))
        return FALSE;

    // get file
    CHTTP Http;
    if (!Http.Get(UrlOfLastVersionInfoFile,&VersionInfoFileContent,&VersionInfoFileContentSize))
    {
        if (bDisplayDialog)
            CHTTP::ShowLastError();
        goto CleanUp;
    }

    // convert xml content to upper to do insensitive search
    pszContentUpper=strdup((char*)VersionInfoFileContent);
    strupr(pszContentUpper);

    char* pszVersion;
    DWORD VersionLength;
    char* pszDescription;
    DWORD DescriptionLength;
    char* pPointerAfterEndingMarkup;
    if(!CSoftwareUpdate::ReadXMLMarkupContent(pszContentUpper,XML_MARKUP_VERSION,&pszVersion,&VersionLength,&pPointerAfterEndingMarkup))
    {
        if (bDisplayDialog)
            MessageBox(NULL,_T("Invalid update information file"),_T("Error"),MB_OK|MB_ICONERROR);
        goto CleanUp;
    }
    // get non upper value (avoid to act on upper buffer too for next markup searches)
    pszVersion=(char*)VersionInfoFileContent+(pszVersion-pszContentUpper);
    pszVersion[VersionLength]=0;


    BOOL NewVersionExists=TRUE;
    TCHAR PrettyVersion[50];
    
#if (defined(UNICODE)||defined(_UNICODE))
    CVersion::GetPrettyVersion(Version.FileVersion,VersionNbDigits,PrettyVersion,50);
    CAnsiUnicodeConvert::UnicodeToAnsi(PrettyVersion,&pszAnsi);
    if(strcmp(pszVersion,pszAnsi)==0)
        NewVersionExists=FALSE;
    free(pszAnsi);
#else
    CVersion::GetPrettyVersion(Version.FileVersion,VersionNbDigits,PrettyVersion,50);
    if(strcmp(pszVersion,PrettyVersion)==0)
        NewVersionExists=FALSE;
#endif
    if (!NewVersionExists)
    {
        if (bDisplayDialog)
            MessageBox(NULL, _T("Your software is up to date"),_T("Information"),MB_OK|MB_ICONINFORMATION);
        bSuccess=TRUE;
        goto CleanUp;
    }
    // else : NewVersionExists
    *pbNewVersionIsAvailable = TRUE;

    if (bDisplayDialog)
    {
        // read changes informations
        CSoftwareUpdate::ReadXMLMarkupContent(pszContentUpper,XML_MARKUP_DESCRIPTION,&pszDescription,&DescriptionLength,&pPointerAfterEndingMarkup);
        // get non upper value (avoid to act on upper buffer too for next markup searches)
        pszDescription=(char*)VersionInfoFileContent+(pszDescription-pszContentUpper);
        if (pszDescription)
            pszDescription[DescriptionLength]=0;

        pszReport=new char[MAX_PATH+VersionLength+DescriptionLength];

        sprintf(pszReport,"A new version (%s) is available\r\n",pszVersion);
        if (pszDescription)
        {
            if (*pszDescription)
            {
                strcat(pszReport,"Changes : ");
                strcat(pszReport,pszDescription);
                strcat(pszReport,"\r\n");
            }
        }
        strcat(pszReport,"\r\nDo you want to download new version now ?");

#if (defined(UNICODE)||defined(_UNICODE))
        TCHAR* pszUnicode;
        CAnsiUnicodeConvert::AnsiToUnicode(pszReport,&pszUnicode);
        CSoftwareUpdate::DisplayNewVersionInfos(pszUnicode,DownloadLink);
        free(pszUnicode);
#else
        CSoftwareUpdate::DisplayNewVersionInfos(pszReport,DownloadLink);
#endif
    }

    bSuccess=TRUE;
CleanUp:
    if (pszReport)
        delete[] pszReport;
    if (pszContentUpper)
        free(pszContentUpper);
    if (VersionInfoFileContent)
        delete[] VersionInfoFileContent;
    return bSuccess;
}
//-----------------------------------------------------------------------------
// Name: ReadXMLMarkupContent
// Object: read xml content. This func allow version soft read ascii saved files
//          or ansi version read unicode saved files
// Parameters :
//     in  : TCHAR* FullString : buffer supposed to contain markup
//           TCHAR* Markup : markup
//     out : TCHAR** ppszContent : content of the markup in the same encoding as FullString
//           DWORD* pContentLength : content length in TCHAR
//           TCHAR** pPointerAfterEndingMarkup : pointer after the markup
//     return : TRUE if Markup found, FALSE else
//-----------------------------------------------------------------------------
BOOL CSoftwareUpdate::ReadXMLMarkupContent(char* FullString,char* Markup,char** ppszContent,DWORD* pContentLength,char** pPointerAfterEndingMarkup)
{
    BOOL bSuccess=FALSE;
    *ppszContent=0;
    *pContentLength=0;
    *pPointerAfterEndingMarkup=0;

    if (IsBadReadPtr(FullString,sizeof(char*)))
        return FALSE;
    if (*FullString==0)
        return FALSE;

    size_t MarkupSize=strlen(Markup);
    char* pszStartTag=new char[MarkupSize+3];
    char* pszEndTag=new char[MarkupSize+4];
    char* pszNoDataTag=NULL;
    char* pszStartTagPos;
    char* pszEndTagPos;
    char* pszNoDataTagPos;

    // make xml start tag and end tag (Tag --> <Tag> and </Tag>)
    sprintf(pszStartTag,"<%s>",Markup);
    sprintf(pszEndTag,"</%s>",Markup);
    

    // search xml start tag and end tag
    pszStartTagPos=strstr(FullString,pszStartTag);
    pszEndTagPos=strstr(FullString,pszEndTag);
    // if none found
    if ((pszStartTagPos==0)||(pszEndTagPos==0))
    {
        if ((pszStartTagPos==0)&&(pszEndTagPos==0))
        {
            pszNoDataTag=new char[MarkupSize+5];
            sprintf(pszNoDataTag,"<%s />",Markup);
            pszNoDataTagPos=strstr(FullString,pszNoDataTag);
            if (pszNoDataTagPos)
            {
                *ppszContent=pszNoDataTagPos;
                *pContentLength=0;
                *pPointerAfterEndingMarkup=pszNoDataTagPos+MarkupSize+4;
                bSuccess=TRUE;
            }   
        }

        goto CleanUp;
    }
    // if bad positions
    if (pszEndTagPos<pszStartTagPos)
        goto CleanUp;

    // get content of markup
    *ppszContent=pszStartTagPos+MarkupSize+2;
    *pContentLength=(DWORD)(pszEndTagPos-*ppszContent);
    *pPointerAfterEndingMarkup=pszEndTagPos+MarkupSize+3;

    bSuccess=TRUE;
CleanUp:
    if (pszNoDataTag)
        delete[] pszNoDataTag;
    delete[] pszStartTag;
    delete[] pszEndTag;

    return bSuccess;
}

//-----------------------------------------------------------------------------
// Name: DisplayNewVersionInfos
// Object: Display new version information and open default download manager if 
//         user wants to download new version
// Parameters :
//     in  : TCHAR* pszNewVersionDownloadQuery : query text to download new version
//           TCHAR* DownloadLink : download link (url)
//     out :
//     return : 
//-----------------------------------------------------------------------------
void CSoftwareUpdate::DisplayNewVersionInfos(TCHAR* pszNewVersionDownloadQuery,TCHAR* DownloadLink)
{
    if (MessageBox(NULL,pszNewVersionDownloadQuery,_T("Update"),MB_YESNO|MB_ICONINFORMATION)==IDYES)
    {
        ShellExecute(NULL,_T("open"),DownloadLink,NULL,NULL,SW_SHOWDEFAULT);
    }
}